#include <TFT_eSPI.h>
#include <FastLED.h>
#include <SPI.h>
#include <Wire.h>
#include "bmp1.h"
#include "bmp2.h"
#include "bmp3.h"
#include "bmp4.h"
#include "bmp5.h"
#include "bmp6.h"

#ifndef TFT_DISPOFF
#define TFT_DISPOFF 0x28
#endif

#ifndef TFT_SLPIN
#define TFT_SLPIN   0x10
#endif

#define LED_PIN     2
#define NUM_LEDS    1
#define BRIGHTNESS  50
#define LED_TYPE    WS2811
#define COLOR_ORDER GRB
CRGB leds[NUM_LEDS];
#define UPDATES_PER_SECOND 100
CRGBPalette16 currentPalette;
TBlendType    currentBlending;

extern CRGBPalette16 myRedWhiteBluePalette;
extern const TProgmemPalette16 myRedWhiteBluePalette_p PROGMEM;

#define TIME 3000
#define POWER_ADC 27//ADC引脚
#define LED1 25
#define LED2 26
#define LED1_OFF   digitalWrite(LED1, HIGH)//关灯1
#define LED1_ON    digitalWrite(LED1, LOW)//开灯1
#define LED1_PWM   digitalWrite(LED1, !digitalRead(LED1))//灯1闪烁
#define LED2_OFF   digitalWrite(LED2, HIGH)//关灯2
#define LED2_ON    digitalWrite(LED2, LOW)//开灯2
#define LED2_PWM   digitalWrite(LED2, !digitalRead(LED2))//灯2闪烁
 
int freq1 = 500;    // 频率
int channel1 = 0;    // 通道0，共16个通道，0~15
int resolution1 = 10;   // 分辨率，取值0~20，duty最大取值为2^resolution-1
 
int freq2 = 500;    // 频率
int channel2 = 1;    // 通道1，共16个通道，0~15
int resolution2 = 10;   // 分辨率，取值0~20，duty最大取值为2^resolution-1

TFT_eSPI tft = TFT_eSPI(135, 240); // Invoke custom library

char buff[512];
int vref = 1100;
int btnCick = false;

void showImage1(int32_t x, int32_t y, int32_t w, int32_t h, const uint16_t *data);
void showImage2(int32_t x, int32_t y, int32_t w, int32_t h, const uint16_t *data);
void SetupTotallyRandomPalette();
void SetupBlackAndWhiteStripedPalette();
void SetupPurpleAndGreenPalette();
void FillLEDsFromPaletteColors( uint8_t colorIndex);
void ChangePalettePeriodically();

void setup()
{
    Serial.begin(115200);
    Serial.println("Start");

    adcAttachPin(POWER_ADC);//将引脚连接到ADC
    adcStart(POWER_ADC);//在连接的引脚总线上开始ADC转换
    analogReadResolution(16);//设置aliogRead返回值的分辨率

    ledcSetup(channel1, freq1, resolution1); // 设置通道0
    ledcSetup(channel2, freq2, resolution2); // 设置通道1
    ledcAttachPin(LED1, channel1);  // 将通道0与引脚19连接
    ledcAttachPin(LED2, channel2);  // 将通道1与引脚22连接

    tft.init();
    tft.setRotation(1);
    tft.fillScreen(TFT_BLACK);
    tft.setTextSize(2);
    tft.setTextColor(TFT_MAGENTA);
    tft.setCursor(0, 0);
    tft.setTextDatum(MC_DATUM);
    tft.setTextSize(1);

    if (TFT_BL > 0) { // TFT_BL has been set in the TFT_eSPI library in the User Setup file TTGO_T_Display.h
         pinMode(TFT_BL, OUTPUT); // Set backlight pin to output mode
         digitalWrite(TFT_BL, TFT_BACKLIGHT_ON); // Turn backlight on. TFT_BACKLIGHT_ON has been set in the TFT_eSPI library in the User Setup file TTGO_T_Display.h
    }
    tft.setRotation(1);
    tft.fillScreen(TFT_WHITE);
    tft.setSwapBytes(true);

    FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
    FastLED.setBrightness(  BRIGHTNESS );
    
    currentPalette = RainbowColors_p;
    currentBlending = LINEARBLEND;
}

void loop()
{
  showImage2(0, 0, 240, 135, bmp1);
  delay(TIME);
  showImage2(0, 0, 240, 135, bmp2);
  delay(TIME);
  showImage2(0, 0, 240, 135, bmp3);
  delay(TIME);
  showImage2(0, 0, 240, 135, bmp4);
  delay(TIME);
  showImage2(0, 0, 240, 135, bmp5);
  delay(TIME);
  showImage2(0, 0, 240, 135, bmp6);
  delay(TIME);

  Serial.print("系统电压是:  ");
  Serial.print(2*((analogRead(POWER_ADC)*3.3)/65535)+0.4);
  Serial.println(" V");
  delay(1000);

  // 逐渐变亮
  for (int dutyCycle = 0; dutyCycle <= 1023; dutyCycle = dutyCycle + 5)
  {
    ledcWrite(channel1, dutyCycle);  // 输出PWM
    ledcWrite(channel2, 1023 - dutyCycle);  // 输出PWM
    delay(1);
  }
 
  // 逐渐变暗
  for (int dutyCycle = 1023; dutyCycle >= 0; dutyCycle = dutyCycle - 5)
  {
    ledcWrite(channel1, dutyCycle);  // 输出PWM
    ledcWrite(channel2, 1023 - dutyCycle);  // 输出PWM
    delay(1);
  }

  ledcWrite(channel1, 0);  // 输出PWM
  ledcWrite(channel2, 0);  // 输出PWM

  ChangePalettePeriodically();
    
    static uint8_t startIndex = 0;
    startIndex = startIndex + 1; /* motion speed */
    
    FillLEDsFromPaletteColors( startIndex);
    
    FastLED.show();
    FastLED.delay(1000 / UPDATES_PER_SECOND);
}

#define PI_BUF_SIZE 128
void showImage1(int32_t x, int32_t y, int32_t w, int32_t h, const uint16_t *data){
  int32_t dx = 0;
  int32_t dy = 0;
  int32_t dw = w;
  int32_t dh = h;

  if (x < 0) { dw += x; dx = -x; x = 0; }
  if (y < 0) { dh += y; dy = -y; y = 0; }

  if (dw < 1 || dh < 1) return;

  CS_L;

  data += dx + dy * w;

  uint16_t  buffer[PI_BUF_SIZE];
  uint16_t* pix_buffer = buffer;

  tft.setWindow(x, y, x + dw - 1, y + dh - 1);

  // Work out the number whole buffers to send
  uint16_t nb = (dw * dh) / PI_BUF_SIZE;

  // Fill and send "nb" buffers to TFT
  for (int32_t i = 0; i < nb; i++) {
    for (int32_t j = 0; j < PI_BUF_SIZE; j++) {
      pix_buffer[j] = pgm_read_word(&data[i * PI_BUF_SIZE + j]);
    }
    tft.pushPixels(pix_buffer, PI_BUF_SIZE);
  }

  // Work out number of pixels not yet sent
  uint16_t np = (dw * dh) % PI_BUF_SIZE;

  // Send any partial buffer left over
  if (np) {
    for (int32_t i = 0; i < np; i++)
    {
      pix_buffer[i] = pgm_read_word(&data[nb * PI_BUF_SIZE + i]);
    }
    tft.pushPixels(pix_buffer, np);
  }

  CS_H;
}

void showImage2(int32_t x, int32_t y, int32_t w, int32_t h, const uint16_t *data){
  int32_t dx = 0;
  int32_t dy = 0;
  int32_t dw = w;
  int32_t dh = h*2;

  if (x < 0) { dw += x; dx = -x; x = 0; }
  if (y < 0) { dh += y; dy = -y; y = 0; }

  if (dw < 1 || dh < 1) return;

  CS_L;

  data += dx + dy * w;

  uint16_t  buffer[PI_BUF_SIZE];
  uint16_t* pix_buffer = buffer;
  uint16_t  high,low;

  tft.setWindow(x, y, x + dw - 1, y + dh - 1);

  // Work out the number whole buffers to send
  uint16_t nb = (dw * dh) / (2 * PI_BUF_SIZE);

  // Fill and send "nb" buffers to TFT
  for (int32_t i = 0; i < nb; i++) {
    for (int32_t j = 0; j < PI_BUF_SIZE; j++) {
      high = pgm_read_word(&data[(i * 2 * PI_BUF_SIZE) + 2 * j + 1]);
      low = pgm_read_word(&data[(i * 2 * PI_BUF_SIZE) + 2 * j ]);
      pix_buffer[j] = (high<<8)+low;
    }
    tft.pushPixels(pix_buffer, PI_BUF_SIZE);
  }

  // Work out number of pixels not yet sent
  uint16_t np = (dw * dh) % (2 * PI_BUF_SIZE);

  // Send any partial buffer left over
  if (np) {
    for (int32_t i = 0; i < np; i++)
    {
      high = pgm_read_word(&data[(nb * 2 * PI_BUF_SIZE) + 2 * i + 1]);
      low = pgm_read_word(&data[(nb * 2 * PI_BUF_SIZE) + 2 * i ]);
      pix_buffer[i] = (high<<8)+low;
    }
    tft.pushPixels(pix_buffer, np);
  }

  CS_H;
}

// This function fills the palette with totally random colors.
void SetupTotallyRandomPalette()
{
    for( int i = 0; i < 16; i++) {
        currentPalette[i] = CHSV( random8(), 255, random8());
    }
}

// This function sets up a palette of black and white stripes,
// using code.  Since the palette is effectively an array of
// sixteen CRGB colors, the various fill_* functions can be used
// to set them up.
void SetupBlackAndWhiteStripedPalette()
{
    // 'black out' all 16 palette entries...
    fill_solid( currentPalette, 16, CRGB::Black);
    // and set every fourth one to white.
    currentPalette[0] = CRGB::White;
    currentPalette[4] = CRGB::White;
    currentPalette[8] = CRGB::White;
    currentPalette[12] = CRGB::White;
    
}

// This function sets up a palette of purple and green stripes.
void SetupPurpleAndGreenPalette()
{
    CRGB purple = CHSV( HUE_PURPLE, 255, 255);
    CRGB green  = CHSV( HUE_GREEN, 255, 255);
    CRGB black  = CRGB::Black;
    
    currentPalette = CRGBPalette16(
                                   green,  green,  black,  black,
                                   purple, purple, black,  black,
                                   green,  green,  black,  black,
                                   purple, purple, black,  black );
}


// This example shows how to set up a static color palette
// which is stored in PROGMEM (flash), which is almost always more
// plentiful than RAM.  A static PROGMEM palette like this
// takes up 64 bytes of flash.
const TProgmemPalette16 myRedWhiteBluePalette_p PROGMEM =
{
    CRGB::Red,
    CRGB::Gray, // 'white' is too bright compared to red and blue
    CRGB::Blue,
    CRGB::Black,
    
    CRGB::Red,
    CRGB::Gray,
    CRGB::Blue,
    CRGB::Black,
    
    CRGB::Red,
    CRGB::Red,
    CRGB::Gray,
    CRGB::Gray,
    CRGB::Blue,
    CRGB::Blue,
    CRGB::Black,
    CRGB::Black
};

void FillLEDsFromPaletteColors( uint8_t colorIndex)
{
    uint8_t brightness = 255;
    
    for( int i = 0; i < NUM_LEDS; i++) {
        leds[i] = ColorFromPalette( currentPalette, colorIndex, brightness, currentBlending);
        colorIndex += 3;
    }
}


// There are several different palettes of colors demonstrated here.
//
// FastLED provides several 'preset' palettes: RainbowColors_p, RainbowStripeColors_p,
// OceanColors_p, CloudColors_p, LavaColors_p, ForestColors_p, and PartyColors_p.
//
// Additionally, you can manually define your own color palettes, or you can write
// code that creates color palettes on the fly.  All are shown here.

void ChangePalettePeriodically()
{
    uint8_t secondHand = (millis() / 1000) % 60;
    static uint8_t lastSecond = 99;
    
    if( lastSecond != secondHand) {
        lastSecond = secondHand;
        if( secondHand ==  0)  { currentPalette = RainbowColors_p;         currentBlending = LINEARBLEND; }
        if( secondHand == 10)  { currentPalette = RainbowStripeColors_p;   currentBlending = NOBLEND;  }
        if( secondHand == 15)  { currentPalette = RainbowStripeColors_p;   currentBlending = LINEARBLEND; }
        if( secondHand == 20)  { SetupPurpleAndGreenPalette();             currentBlending = LINEARBLEND; }
        if( secondHand == 25)  { SetupTotallyRandomPalette();              currentBlending = LINEARBLEND; }
        if( secondHand == 30)  { SetupBlackAndWhiteStripedPalette();       currentBlending = NOBLEND; }
        if( secondHand == 35)  { SetupBlackAndWhiteStripedPalette();       currentBlending = LINEARBLEND; }
        if( secondHand == 40)  { currentPalette = CloudColors_p;           currentBlending = LINEARBLEND; }
        if( secondHand == 45)  { currentPalette = PartyColors_p;           currentBlending = LINEARBLEND; }
        if( secondHand == 50)  { currentPalette = myRedWhiteBluePalette_p; currentBlending = NOBLEND;  }
        if( secondHand == 55)  { currentPalette = myRedWhiteBluePalette_p; currentBlending = LINEARBLEND; }
    }
}